package com.tinxing.bp.security;


import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.tinxing.bp.commons.utils.ToolUtil;
import com.tinxing.bp.modules.permission.dao.PermissionDao;
import com.tinxing.bp.modules.role.entity.Role;
import com.tinxing.bp.modules.role.service.IRoleService;
import com.tinxing.bp.modules.user.entity.UserInfo;
import com.tinxing.bp.modules.user.entity.UserRole;
import com.tinxing.bp.modules.user.service.IUserInfoService;
import com.tinxing.bp.modules.user.service.IUserRoleService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: 处理用户登录认证逻辑
 * @author: znegyu
 * @create: 2020-12-08 10:38
 **/
@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private IUserInfoService userInfoService;
    @Resource
    private IRoleService roleService;
    @Resource
    private IUserRoleService userRoleService;
    @Resource
    private PermissionDao permissionDao;

    @Value("${server.servlet.context-path}")
    public String apiPrefix;

    /**
     * 通过账号从数据库查询出当前登录用户的信息,返回一个UserDetails
     * (Spring-Security需要根据这个返回的对象来判断用户是否登录成功!)
     * 将认证授权信息加入Redis缓存,减少重复访问数据库次数
     *
     * @param account -登录用户的账号
     * @return -返回一个UserDetails对象
     * @throws UsernameNotFoundException -用户不存在
     */
    @Override
    @Cacheable(value = "UserDetailsCacheInJinQue", key = "#account")
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        //1.获取用户信息
        if (ToolUtil.isEmpty(account)) {
            throw new UsernameNotFoundException("账号为空!");
        }
        UserInfo userInfo = new LambdaQueryChainWrapper<>(userInfoService.getBaseMapper()).eq(UserInfo::getAccount,account).one();
        if (userInfo == null) {
            throw new UsernameNotFoundException("账号不存在!");
        }
        //2.获取用户角色信息
        List<UserRole> userRoles = new LambdaQueryChainWrapper<>(userRoleService.getBaseMapper()).eq(UserRole::getUserId, userInfo.getId()).list();
        List<String> roleIds = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
        // 该用户拥有的角色集合
        List<Role> roleList = new LambdaQueryChainWrapper<>(roleService.getBaseMapper()).in(Role::getId,roleIds).list();
        //角色也是一种特殊的权限
        List<String> allPermission = roleList.stream().map(t -> "ROLE_" + t.getRoleName()).collect(Collectors.toList());
        //3.获取用户接口权限列表
        List<String> permissionList = permissionDao.getPermissionListByAccount(account);
        permissionList = permissionList.stream().map(t -> apiPrefix + t).collect(Collectors.toList());
        //角色权限和普通权限合并
        allPermission.addAll(permissionList);
        //返回用户信息和用户权限合集给security管理
        return new LoginUserDetails(userInfo, AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", allPermission)));
    }
}
